Skip to content

Add webviewer batching#293

Merged
eluce2 merged 11 commits into
mainfrom
codex/webviewer-batching
Jun 25, 2026
Merged

Add webviewer batching#293
eluce2 merged 11 commits into
mainfrom
codex/webviewer-batching

Conversation

@eluce2

@eluce2 eluce2 commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Summary:

  • enable WebViewerAdapter request batching by default
  • set default maximum batch size to 20
  • keep per-request batching controls
  • make batch: false disable coalescing while still sending single-request batch calls until legacy fallback is triggered
  • page listAll/findAll through bounded adapter read requests
  • document default batching, tuning guidance, add-on update requirement, and all-record helper behavior

Test:

  • pnpm --filter @proofkit/docs lint
  • pnpm --filter @proofkit/webviewer lint
  • pnpm --filter @proofkit/webviewer typecheck
  • pnpm --filter @proofkit/webviewer test
  • pnpm run ci

Summary by CodeRabbit

  • New Features

    • Added optional batching for Web Viewer Data API requests to reduce repeated calls.
    • Introduced new listAll and findAll support for adapter-based pagination.
    • Added per-request control to enable or disable batching.
  • Bug Fixes

    • Improved handling for older FileMaker add-on scripts by warning and falling back to individual requests when batching isn’t supported.
    • Better response handling for batched requests, including partial failures.

@vercel

vercel Bot commented Jun 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
proofkit-docs Ready Ready Preview, Comment Jun 24, 2026 10:46pm

Request Review

@eluce2 eluce2 mentioned this pull request Jun 24, 2026
@changeset-bot

changeset-bot Bot commented Jun 24, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2b628e3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@proofkit/webviewer Minor
@proofkit/fmdapi Minor
@proofkit/typegen Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jun 24, 2026

Copy link
Copy Markdown

Open in StackBlitz

@proofkit/better-auth

pnpm add https://pkg.pr.new/proofsh/proofkit/@proofkit/better-auth@293

@proofkit/fmdapi

pnpm add https://pkg.pr.new/proofsh/proofkit/@proofkit/fmdapi@293

@proofkit/fmodata

pnpm add https://pkg.pr.new/proofsh/proofkit/@proofkit/fmodata@293

@proofkit/typegen

pnpm add https://pkg.pr.new/proofsh/proofkit/@proofkit/typegen@293

@proofkit/webviewer

pnpm add https://pkg.pr.new/proofsh/proofkit/@proofkit/webviewer@293

commit: 2b628e3

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds opt-in batching to WebViewerAdapter, adds listAll and findAll adapter methods with pagination, updates fmdapi client delegation and normalization, and adds docs and tests for the new request flows.

Changes

WebViewerAdapter batching and adapter-level pagination

Layer / File(s) Summary
Adapter contracts and batch options
packages/fmdapi/src/adapters/core.ts, packages/webviewer/src/adapter.ts
BaseRequest gains batch?: boolean, Adapter marks listAll/findAll optional, and the webviewer adapter adds batching options plus request-body normalization helpers.
Client normalization and adapter fast paths
packages/fmdapi/src/client.ts
DataApi request typing gains batch?: boolean; list and find request normalization helpers are added; _list and _find use the new normalization paths; listAll and findAll delegate to adapter methods when available.
WebViewerAdapter batching pipeline and methods
packages/webviewer/src/adapter.ts, packages/webviewer/tests/adapter.test.ts, packages/fmdapi/tests/client-methods.test.ts
WebViewerAdapter adds queue-based batching with timer and size flushing, legacy 1708 fallback handling, listAll and findAll pagination, and per-call batch forwarding on existing methods, with matching adapter and client tests.
Docs, metadata, and changeset
apps/docs/content/docs/webviewer/batching.mdx, apps/docs/content/docs/webviewer/fmdapi.mdx, apps/docs/content/docs/webviewer/meta.json, .changeset/quick-bats-queue.md
The webviewer docs gain a new batching page, the fmdapi docs add batching and adapter pagination sections, the webviewer metadata includes the new page, and a changeset records minor bumps for @proofkit/webviewer and @proofkit/fmdapi.

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant DataApi
  participant WebViewerAdapter
  participant fmFetch

  App->>DataApi: listAll() / findAll() / list() / find()
  DataApi->>WebViewerAdapter: normalized request
  alt adapter pagination fast path
    WebViewerAdapter->>fmFetch: bounded read request
    fmFetch-->>WebViewerAdapter: page with foundCount
    WebViewerAdapter->>fmFetch: follow-up bounded reads
    fmFetch-->>WebViewerAdapter: additional pages
  else batch-enabled request
    WebViewerAdapter->>WebViewerAdapter: enqueue and flush
    WebViewerAdapter->>fmFetch: batch envelope
    fmFetch-->>WebViewerAdapter: batched responses
  end
  WebViewerAdapter-->>DataApi: GetResponse
  DataApi-->>App: records
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: adding opt-in batching to the WebViewer adapter and related docs.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/webviewer-batching

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/fmdapi/src/client.ts (1)

179-192: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract named FileMaker dateformat codes.

The 0/1/2 mapping is domain-specific and the @ts-expect-error hides the string conversion. Named constants make the adapter payload clearer and keep the normalization local.

Proposed refactor
+  const FILEMAKER_DATE_FORMAT_US = "0";
+  const FILEMAKER_DATE_FORMAT_FILE_LOCALE = "1";
+  const FILEMAKER_DATE_FORMAT_ISO8601 = "2";
+
   function normalizeFindRequest(args: FindMethodArgs): {
     fetch?: RequestInit;
     ignoreEmptyResult: boolean;
     params: FindOptions["data"];
     timeout?: number;
@@
     if ("sort" in params && params.sort !== undefined && !Array.isArray(params.sort)) {
       params.sort = [params.sort];
     }
+    let normalizedDateformats: string | undefined;
     if ("dateformats" in params && params.dateformats !== undefined) {
-      let dateFormatValue: number;
+      normalizedDateformats = FILEMAKER_DATE_FORMAT_US;
       if (params.dateformats === "US") {
-        dateFormatValue = 0;
+        normalizedDateformats = FILEMAKER_DATE_FORMAT_US;
       } else if (params.dateformats === "file_locale") {
-        dateFormatValue = 1;
+        normalizedDateformats = FILEMAKER_DATE_FORMAT_FILE_LOCALE;
       } else if (params.dateformats === "ISO8601") {
-        dateFormatValue = 2;
-      } else {
-        dateFormatValue = 0;
+        normalizedDateformats = FILEMAKER_DATE_FORMAT_ISO8601;
       }
-      // `@ts-expect-error` FM wants a string, so this is fine
-      params.dateformats = dateFormatValue.toString();
     }

     return {
       fetch,
       ignoreEmptyResult,
-      params: { ...params, query } as FindOptions["data"],
+      params: {
+        ...params,
+        ...(normalizedDateformats === undefined ? {} : { dateformats: normalizedDateformats }),
+        query,
+      } as FindOptions["data"],
       timeout,
     };
   }

As per coding guidelines, "**/*.{js,jsx,ts,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/fmdapi/src/client.ts` around lines 179 - 192, The dateformat
normalization in the client adapter uses magic numbers and an inline
ts-expect-error, so extract the FileMaker codes into descriptive constants and
keep the conversion logic readable. Update the dateformat handling in client.ts
around the params.dateformats normalization to use named symbols for the US,
file_locale, and ISO8601 values, and keep the string conversion localized in
that branch so the payload shape remains unchanged while the meaning is
explicit.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/fmdapi/src/client.ts`:
- Around line 179-192: The dateformat normalization in the client adapter uses
magic numbers and an inline ts-expect-error, so extract the FileMaker codes into
descriptive constants and keep the conversion logic readable. Update the
dateformat handling in client.ts around the params.dateformats normalization to
use named symbols for the US, file_locale, and ISO8601 values, and keep the
string conversion localized in that branch so the payload shape remains
unchanged while the meaning is explicit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 28af687b-89fd-4633-ab6f-be86ce9c8230

📥 Commits

Reviewing files that changed from the base of the PR and between 319b026 and 8283691.

📒 Files selected for processing (7)
  • .changeset/quick-bats-queue.md
  • apps/docs/content/docs/webviewer/fmdapi.mdx
  • packages/fmdapi/src/adapters/core.ts
  • packages/fmdapi/src/client.ts
  • packages/fmdapi/tests/client-methods.test.ts
  • packages/webviewer/src/adapter.ts
  • packages/webviewer/tests/adapter.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/webviewer/src/adapter.ts (1)

145-149: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Guard empty messages before reading code.

resp.messages?.[0].code still dereferences .code when messages is an empty array, so malformed FileMaker envelopes reject with a TypeError instead of the intended FileMakerError.

Proposed fix
   private handleDataApiResponse(resp: clientTypes.RawFMResponse): unknown {
-    if (resp.messages?.[0].code !== "0") {
+    const code = resp.messages?.[0]?.code ?? "500";
+    if (code !== "0") {
       throw new FileMakerError(
-        resp?.messages?.[0].code ?? "500",
-        `Filemaker Data API failed with (${resp.messages?.[0].code}): ${JSON.stringify(resp, null, 2)}`,
+        code,
+        `Filemaker Data API failed with (${code}): ${JSON.stringify(resp, null, 2)}`,
       );
     }

As per coding guidelines: “Use optional chaining (?.) and nullish coalescing (??) for safer property access.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/webviewer/src/adapter.ts` around lines 145 - 149, The FileMaker
response check in handleDataApiResponse still reads code from resp.messages?.[0]
without guarding the case where messages is an empty array, which can throw a
TypeError before FileMakerError is raised. Update the resp.messages validation
to safely handle both missing and empty messages using optional chaining and
nullish coalescing, and keep the FileMakerError construction in
handleDataApiResponse as the single failure path when the first message code is
not "0" or is unavailable.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/webviewer/src/adapter.ts`:
- Around line 271-280: The legacy fallback in executeUnbatchedRequests currently
runs queued requests concurrently with Promise.all, which can reorder
create/update/delete side effects relative to the original batch order. Change
the flow in executeUnbatchedRequests to process each QueuedBatchRequest
sequentially in array order, awaiting one request before starting the next,
while still resolving or rejecting each request individually. Keep the behavior
inside executeSingleRequest unchanged and preserve the existing
request.resolve/request.reject handling.

---

Outside diff comments:
In `@packages/webviewer/src/adapter.ts`:
- Around line 145-149: The FileMaker response check in handleDataApiResponse
still reads code from resp.messages?.[0] without guarding the case where
messages is an empty array, which can throw a TypeError before FileMakerError is
raised. Update the resp.messages validation to safely handle both missing and
empty messages using optional chaining and nullish coalescing, and keep the
FileMakerError construction in handleDataApiResponse as the single failure path
when the first message code is not "0" or is unavailable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: aa5df4bb-b6d3-4376-8262-5e3c8cfd4ebf

📥 Commits

Reviewing files that changed from the base of the PR and between 8283691 and e0b287c.

📒 Files selected for processing (6)
  • .changeset/tiny-lamps-tap.md
  • apps/docs/content/docs/webviewer/batching.mdx
  • apps/docs/content/docs/webviewer/fmdapi.mdx
  • apps/docs/content/docs/webviewer/meta.json
  • packages/webviewer/src/adapter.ts
  • packages/webviewer/tests/adapter.test.ts
✅ Files skipped from review due to trivial changes (3)
  • apps/docs/content/docs/webviewer/meta.json
  • .changeset/tiny-lamps-tap.md
  • apps/docs/content/docs/webviewer/batching.mdx

Comment on lines +271 to +280
private async executeUnbatchedRequests(requests: QueuedBatchRequest[]) {
await Promise.all(
requests.map(async (request) => {
try {
request.resolve(await this.executeSingleRequest(request.payload));
} catch (error) {
request.reject(error);
}
}),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve request order during legacy fallback.

When batching is unsupported, Promise.all(requests.map(...)) replays queued requests concurrently. Since the same queue can contain create, update, and delete, this can reorder side effects compared with the batch request order.

Proposed fix
   private async executeUnbatchedRequests(requests: QueuedBatchRequest[]) {
-    await Promise.all(
-      requests.map(async (request) => {
-        try {
-          request.resolve(await this.executeSingleRequest(request.payload));
-        } catch (error) {
-          request.reject(error);
-        }
-      }),
-    );
+    for (const request of requests) {
+      try {
+        request.resolve(await this.executeSingleRequest(request.payload));
+      } catch (error) {
+        request.reject(error);
+      }
+    }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private async executeUnbatchedRequests(requests: QueuedBatchRequest[]) {
await Promise.all(
requests.map(async (request) => {
try {
request.resolve(await this.executeSingleRequest(request.payload));
} catch (error) {
request.reject(error);
}
}),
);
private async executeUnbatchedRequests(requests: QueuedBatchRequest[]) {
for (const request of requests) {
try {
request.resolve(await this.executeSingleRequest(request.payload));
} catch (error) {
request.reject(error);
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/webviewer/src/adapter.ts` around lines 271 - 280, The legacy
fallback in executeUnbatchedRequests currently runs queued requests concurrently
with Promise.all, which can reorder create/update/delete side effects relative
to the original batch order. Change the flow in executeUnbatchedRequests to
process each QueuedBatchRequest sequentially in array order, awaiting one
request before starting the next, while still resolving or rejecting each
request individually. Keep the behavior inside executeSingleRequest unchanged
and preserve the existing request.resolve/request.reject handling.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/webviewer/src/adapter.ts (2)

251-271: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Keep internal batch IDs authoritative.

{ id: request.id, ...request.payload } lets a top-level id from body overwrite the queue id, causing response mapping to miss the result. Put id last; using for...of also matches the TS iteration guideline.

Proposed fix
-      const resp = await fmFetch<BatchScriptResponse>(this.scriptName, {
+      const batchRequests: Array<DataApiScriptRequest & { id: string }> = [];
+      for (const request of requests) {
+        batchRequests.push({
+          ...request.payload,
+          id: request.id,
+        });
+      }
+
+      const resp = await fmFetch<BatchScriptResponse>(this.scriptName, {
         batch: true,
-        requests: requests.map((request) => ({
-          id: request.id,
-          ...request.payload,
-        })),
+        requests: batchRequests,
       });

As per coding guidelines, **/*.{ts,tsx}: “Prefer for...of loops over other iteration methods.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/webviewer/src/adapter.ts` around lines 251 - 271, In the batch
request construction inside the adapter’s fmFetch call, the queued request id is
being overwritten by request.payload, which can break response mapping. Update
the request object assembly so the internal queue id remains authoritative by
ensuring the id field is applied last, and switch the requests mapping in this
batch path to a for...of-based build to follow the TS iteration guideline.

Source: Coding guidelines


224-230: 🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift

Keep new arrivals on their own batch window.

drainBatchQueue() keeps looping until the queue is empty, so requests enqueued while the current fmFetch is in flight can be sent immediately when that call returns, before their windowMs timer expires. Snapshot the queue for the current flush, and let later arrivals flush via their own timer/max-size path.

Also applies to: 237-245

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/webviewer/src/adapter.ts` around lines 224 - 230, The batching logic
in batchFlushInProgress/flushBatchQueue/drainBatchQueue is reusing the live
queue, which lets requests added during an in-flight fmFetch get flushed too
early. Change the flush path to snapshot the current batch at the start of
flushBatchQueue and have drainBatchQueue process only that snapshot, so later
arrivals remain queued and wait for their own windowMs timer or max-size trigger
before sending.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/webviewer/src/adapter.ts`:
- Around line 251-271: In the batch request construction inside the adapter’s
fmFetch call, the queued request id is being overwritten by request.payload,
which can break response mapping. Update the request object assembly so the
internal queue id remains authoritative by ensuring the id field is applied
last, and switch the requests mapping in this batch path to a for...of-based
build to follow the TS iteration guideline.
- Around line 224-230: The batching logic in
batchFlushInProgress/flushBatchQueue/drainBatchQueue is reusing the live queue,
which lets requests added during an in-flight fmFetch get flushed too early.
Change the flush path to snapshot the current batch at the start of
flushBatchQueue and have drainBatchQueue process only that snapshot, so later
arrivals remain queued and wait for their own windowMs timer or max-size trigger
before sending.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c8253b42-aafa-4b06-9c95-b2c45145b37b

📥 Commits

Reviewing files that changed from the base of the PR and between e0b287c and b8c4090.

📒 Files selected for processing (8)
  • .changeset/quick-bats-queue.md
  • apps/docs/content/docs/webviewer/batching.mdx
  • apps/docs/content/docs/webviewer/fmdapi.mdx
  • packages/fmdapi/src/adapters/core.ts
  • packages/fmdapi/src/client.ts
  • packages/fmdapi/tests/client-methods.test.ts
  • packages/webviewer/src/adapter.ts
  • packages/webviewer/tests/adapter.test.ts
✅ Files skipped from review due to trivial changes (3)
  • apps/docs/content/docs/webviewer/fmdapi.mdx
  • .changeset/quick-bats-queue.md
  • apps/docs/content/docs/webviewer/batching.mdx
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/fmdapi/src/adapters/core.ts
  • packages/fmdapi/tests/client-methods.test.ts
  • packages/webviewer/tests/adapter.test.ts
  • packages/fmdapi/src/client.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/webviewer/src/adapter.ts (1)

200-205: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Use safe optional chaining for malformed message arrays.

messages?.[0].code still dereferences .code when messages is an empty array, so malformed script/batch responses throw TypeError instead of the intended FileMakerError.

Proposed fix
-    if (resp.messages?.[0].code !== "0") {
+    const messageCode = resp.messages?.[0]?.code;
+    if (messageCode !== "0") {
       throw new FileMakerError(
-        resp?.messages?.[0].code ?? "500",
-        `Filemaker Data API failed with (${resp.messages?.[0].code}): ${JSON.stringify(resp, null, 2)}`,
+        messageCode ?? "500",
+        `Filemaker Data API failed with (${messageCode}): ${JSON.stringify(resp, null, 2)}`,
       );
     }

As per coding guidelines, use optional chaining (?.) and nullish coalescing (??) for safer property access.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/webviewer/src/adapter.ts` around lines 200 - 205, The error handling
in handleDataApiResponse still directly reads resp.messages?.[0].code, which can
throw on malformed or empty messages arrays before FileMakerError is raised.
Update the message code access to use safe optional chaining and nullish
coalescing throughout the FileMakerError branch so adapter.ts handles missing
first entries without TypeError while preserving the intended fallback status
code and message.

Source: Coding guidelines

🧹 Nitpick comments (1)
packages/webviewer/src/adapter.ts (1)

391-392: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid spreading page data in the accumulator loop.

records.push(...page.data) can hit argument-size limits for large pages; append records one-by-one while paginating.

Proposed refactor
       for (const page of pages) {
-        records.push(...(page.data ?? []));
+        for (const record of page.data ?? []) {
+          records.push(record);
+        }
       }

As per coding guidelines, avoid spread syntax in accumulators within loops.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/webviewer/src/adapter.ts` around lines 391 - 392, The accumulator
loop in adapter.ts is using spread syntax to append page results, which can hit
argument-size limits for large pages. Update the records-building logic in the
pagination loop around the page iteration in the relevant adapter method to
append each item individually instead of spreading page.data into records,
keeping the same behavior while avoiding spread in the loop.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/webviewer/src/adapter.ts`:
- Around line 368-389: The pagination loop in paginateAll is using the raw
getBatchOptionsForRequest(batch)?.maxSize value, which can be NaN or Infinity
and break paging behavior. Normalize maxSize the same way as the enqueue/drain
path before assigning pageBatchSize, and keep the logic in adapter.ts aligned
with the existing batch-size normalization used elsewhere in this class.

---

Outside diff comments:
In `@packages/webviewer/src/adapter.ts`:
- Around line 200-205: The error handling in handleDataApiResponse still
directly reads resp.messages?.[0].code, which can throw on malformed or empty
messages arrays before FileMakerError is raised. Update the message code access
to use safe optional chaining and nullish coalescing throughout the
FileMakerError branch so adapter.ts handles missing first entries without
TypeError while preserving the intended fallback status code and message.

---

Nitpick comments:
In `@packages/webviewer/src/adapter.ts`:
- Around line 391-392: The accumulator loop in adapter.ts is using spread syntax
to append page results, which can hit argument-size limits for large pages.
Update the records-building logic in the pagination loop around the page
iteration in the relevant adapter method to append each item individually
instead of spreading page.data into records, keeping the same behavior while
avoiding spread in the loop.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 867aa169-7ac8-4965-8fc8-96e88e7573d3

📥 Commits

Reviewing files that changed from the base of the PR and between b8c4090 and 77c57de.

📒 Files selected for processing (5)
  • .changeset/quick-bats-queue.md
  • apps/docs/content/docs/webviewer/batching.mdx
  • apps/docs/content/docs/webviewer/fmdapi.mdx
  • packages/webviewer/src/adapter.ts
  • packages/webviewer/tests/adapter.test.ts
✅ Files skipped from review due to trivial changes (3)
  • .changeset/quick-bats-queue.md
  • apps/docs/content/docs/webviewer/fmdapi.mdx
  • apps/docs/content/docs/webviewer/batching.mdx

Comment thread packages/webviewer/src/adapter.ts
@eluce2 eluce2 merged commit 5c9815e into main Jun 25, 2026
18 checks passed
@eluce2 eluce2 deleted the codex/webviewer-batching branch June 25, 2026 13:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant